/*
 * HttpServer.h
 *
 *  Created on: 2016-7-25
 *      Author: terry
 */

#ifndef HTTPSERVER_H_
#define HTTPSERVER_H_

#include <stdio.h>
#include <stdarg.h>
#include <iosfwd>
#include <string>
#include <map>
#include <sstream>
#include <cstring>

#ifndef MG_ENABLE_HTTP_STREAMING_MULTIPART
#define	MG_ENABLE_HTTP_STREAMING_MULTIPART	1
#endif //

#include "mongoose.h"

#ifdef DELETE
#undef DELETE
#endif //DELETE


class HttpServer;


typedef std::map< std::string, std::string >	StringMap;


struct HttpRequest
{
	HttpServer*	server;
	mg_connection* connection;
	http_message* message;
	StringMap	params;
	std::string token;

	mg_str method;
	mg_str uri;
	mg_str query;
	mg_str body;

	HttpRequest():
		server(),
		connection(),
		message(),
		method(),
		uri(),
		query(),
		body()
	{
	}

	bool get(const char* name, std::string& value);

	bool get(const std::string& name, std::string& value);

	template < class T >
	bool get(const std::string& name, T& value)
	{
		std::string str;
		if (!get(name, str))
		{
			return false;
		}

		if (str.empty())
		{
			return false;
		}

		std::istringstream iss(str);
		iss >> value;
		return true;
	}

	template < class T >
	bool get(const char* name, T& value)
	{
		std::string str;
		if (!get(name, str))
		{
			return false;
		}

		if (str.empty())
		{
			return false;
		}

		std::istringstream iss(str);
		iss >> value;
		return true;
	}

};

struct HttpAsyncResult
{
	mg_connection* connection;
	int code;
	std::string content;

	HttpAsyncResult():
		connection(),
		code()
	{
	}

	explicit HttpAsyncResult(mg_connection* conn):
		connection(conn),
		code()
	{
	}
};


class HttpMethod
{
public:
	static const char* GET;
	static const char* POST;
	static const char* PUT;
	static const char* DELETE;
	static const char* OPTION;

};


/**
 * HTTP 处理器
 */
class HttpHandler
{
public:
	static const int ASYNC_RESULT = -1;

public:
	virtual ~HttpHandler() {}

	/**
	 * 处理REST
	 * @
	 * @param method	HTTP方法, 比如GET/POST
	 * @param uri		相对URI
	 * @param query		查询字符串
	 * @param body		消息体
	 * @param json		返回的JSON结果
	 * @return HTTP状态码, 如果=0 则表示 200, < 0 表示 500. ASYNC_RESULT 表示异步结果
	 */
	virtual int handleJsonApi(HttpRequest& request, std::string& json) =0;

	/**
	 * 上传结束
	 * @param name	变量名称
	 * @param filepath	文件路径
	 */
	virtual void handleUpload(const char* name, const std::string& filepath) =0;

	/**
	 * 处理文件
	 * @param method	方法
	 * @param uri		相对URI
	 * @param query		查询字符串
	 * @param body		消息体
	 * @param resp		响应的消息体
	 * @param mime		响应的MIME类型
	 * @return	HTTP状态码, 如果=0 则表示 200, < 0 表示 500
	 */
	virtual int handleFileApi(HttpRequest& request, std::string& resp, std::string& mime) =0;

	/**
	 * 处理 WebSocket 帧
	 * @param data	帧数据
	 * @param size	数据长度
	 * @param flags 标志
	 */
	virtual void handleWebSocketFrame(unsigned char *data, size_t size, unsigned char flags) =0;

};


/**
 * HTTP 服务器
 *
 */
class HttpServer
{
public:
	static const int MAX_STATIC_PATH = 16;

public:

	virtual ~HttpServer() {}

	/**
	 * 设置Web根目录, 默认当前目录
	 */
	virtual bool setWebRoot(const char* dirPath) =0;

	/**
	 * 设置上传路径
	 * @param dirPath
	 * @return
	 */
	virtual bool setUploadDir(const char* dirPath) =0;

	/**
	 * 设置账户存放文件, 默认为当前目录下 user.htpasswd
	 * 设置UserFile为空, 会禁止用户验证
	*/
	virtual bool setUserFile(const char* filePath) = 0;

	/**
	 * 添加目录
	 * @param url		URL目录
	 * @param dirPath	本地目录
	 * @return true 表示成功
	 */
	virtual bool addDir(const char* url, const char* dirPath) =0;

	/**
	 * 添加api路径
	 * @param prefix
	 * @return
	 */
	virtual bool addJsonApi(const char* prefix) = 0;

	/**
	 * 启动
	 * @param port	本地端口
	 * @param handler	处理器
	 * @return
	 */
	virtual bool start(int port, HttpHandler* handler) =0;

	/**
	 * 停止服务
	 */
	virtual void stop() =0;

	/**
	 * 是否启动
	 * @return
	 */
	virtual bool isStarted() =0;


	/**
	 * 广播推送通知
	 * @param str
	 */
	virtual void broadcast(void *data, size_t len) =0;


	/**
	 * 异步发送HTTP响应
	 * @param nc
	 * @param code	状态码
	 * @param content	内容
	 * @return
	 */
	virtual bool sendResponse(mg_connection* nc, int code, const std::string& content) = 0;

	/**
	 * 异步发送内容
	 * @param nc	连接
	 * @param data	数据指针
	 * @param len	数据长度, < 8K
	 * @return
	 */
	virtual bool send(mg_connection* nc, const void* data, size_t len) =0;

	virtual void broadcastBinary(void *data, size_t len) = 0;

};



#endif /* HTTPSERVER_H_ */
